package com.nulstudio.emotion.text.service;

import com.nulstudio.emotion.text.entity.NulRole;
import com.nulstudio.emotion.text.entity.NulUserDetail;
import com.nulstudio.emotion.text.exception.NulException;
import com.nulstudio.emotion.text.exception.NulExceptionConstants;
import com.nulstudio.emotion.text.mapper.AccountMapper;
import com.nulstudio.emotion.text.mapper.AuthorityMapper;
import org.springframework.lang.NonNull;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

/**
 * Service for authority related operations.
 * @author nullsty
 * @since 2.0
 */
@Service
public final class AuthorityService implements UserDetailsService {

    /**
     * Mapper for authority module.
     */
    private final AuthorityMapper authorityMapper;

    /**
     * Mapper for account module.
     */
    private final AccountMapper accountMapper;

    /**
     * Error message for user not found.
     */
    private static final String EXCEPTION_USER_NOT_FOUND = "User not found.";

    /**
     * Inject mappers for this service.
     * @param authorityMapper mapper for authority module
     * @param accountMapper mapper for account module
     */
    public AuthorityService(AuthorityMapper authorityMapper, AccountMapper accountMapper) {
        this.authorityMapper = authorityMapper;
        this.accountMapper = accountMapper;
    }

    @Override
    @NonNull
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        final NulUserDetail user = accountMapper.getUserByUserName(username);
        if (user == null) {
            throw new UsernameNotFoundException(EXCEPTION_USER_NOT_FOUND);
        }
        return new User(user.getUserName(), user.getPassword(), getRoleById(user.getRole()).toSpringAuthorityList());
    }

    /**
     * Get role information by name.
     * @param name name of the role
     * @return role information
     * @throws NulException when the role does not exist
     */
    @NonNull
    public NulRole getRoleByName(@NonNull String name) throws NulException {
        final NulRole result = authorityMapper.getRoleByName(name);
        if (result == null) {
            throw new NulException(NulExceptionConstants.ROLE_NOT_EXIST);
        }
        return result;
    }

    /**
     * Get role information by ID.
     * @param id ID of the role
     * @return role information
     * @throws NulException when the role does not exist
     */
    @NonNull
    public NulRole getRoleById(int id) throws NulException {
        final NulRole result = authorityMapper.getRoleById(id);
        if (result == null) {
            throw new NulException(NulExceptionConstants.ROLE_NOT_EXIST);
        }
        return result;
    }
}
